/**
 * Date: Thu Apr  7 21:39:48 2022
 * Author: January
 */
#include<stdint.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <libecc/utils/log.h>
#define WITH_STDLIB
#include <libecc/hash/hash_algs.h>

static void show_help() {
    const char *help = \
        "keytool <filename>\n" \ 
        "        -l <length>";
    NOTICE("%s", help);
}

int min(int a, int b) {
    return (a < b)? a : b;
}

int cal_sm3(char* filename, int length) {
    int ret = -1;
    int i;
    const hash_mapping* sm3 = get_hash_by_type(SM3);
    hash_context sm3_ctx;
    FILE* f;
    int cur;
    unsigned char buf[4096];
    
    f = fopen(filename, "rb");
    if (f == NULL) {
        LOG_ERROR("No such file, %s", f);
        ret = -1;
        goto out;
    }

    sm3->hfunc_init(&sm3_ctx);
    while(length > 0) {
        cur = min(4096, length);
        ret = fread(buf, 1, cur, f);
        if (ret <= 0) {
            if (ret < 0) {
                LOG_ERROR("Fail to read file, %s",  strerror(errno));
                goto out;
            }
            break;
        }
        sm3->hfunc_update(&sm3_ctx, buf, ret);
        length -= cur;
    }
    sm3->hfunc_finalize(&sm3_ctx, buf);
    for(i=0; i<32; i++) {
        printf("%02x", buf[i]);
    }
    printf("\n");
    ret = 0;
out:
    return ret;
}

int main(int argc, char* argv[]) {
    char c;
    int option_index;
    int ret = -1;
    char* infile_str = NULL;
    int len = 0x7fffffff;

    while (1) {
        static struct option long_options[] = {
                {"help", no_argument, 0, 0},
                {0,  0,  0,  0 }
        };
        c = getopt_long(argc, argv, "hl",
                        long_options, &option_index);
        if (c == -1)
            break;
        switch (c) {
            case 0:
            case 'h': show_help(); goto out;
            case 'l': len = atoi(optarg);
            case '?': LOG_WARNING("Unknown option, %s", optarg); break;
            default: LOG_WARNING("?? getopt returned character code 0%o ??\n", c);
        }
    }
    if (optind >= argc) {
        show_help();
        ret = -1;
        goto out;
    }
    infile_str = argv[optind];
    ret = cal_sm3(infile_str, len);
    out:
    return ret;
}